/* 
 * Enterprise Library Extensions - DI + ORM.
 * Copyright (C) 2006
 *
 * GNU General Public License
 *
 * This program is free software; you can redistribute 
 * it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 */
using System;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

namespace ELE.EnterpriseLibrary.Data.Configuration
{
  /// <summary>
  /// Defines the settings of Object Relational Mapping for queries, objects, mappings and queryBuilders.
  /// <para>This class is used by the O/R Application Block to retrieve and store data for the configuration 
  /// of the application block</para>
  /// <para>An example of the object mapping settings configuration file:</para>
  /// <code>
  /// &lt;?xml version="1.0" encoding="utf-8" ?>
  /// &lt;configuration>
  ///   &lt;configSections>
  ///     &lt;section name="objectSqlMapping" type="ELE.EnterpriseLibrary.Data.Configuration.ObjectMappingSettings, ELE.EnterpriseLibrary" />
  ///   &lt;/configSections>
  ///   &lt;!-- SQL Mapping definitions-->
  ///   &lt;objectSqlMapping defaultQuery="GetEmployeeById" defaultMapping="Mapping1">
  ///     &lt;queries>
  ///       &lt;add name="GetEmployeeById" 
  ///              sql="select id, name, addressId, birthDate from employee e, employee_extra ee where e.id=@Id and ee.employeeId = e.id">
  ///         &lt;mappings>
  ///           &lt;add name="Mapping1" objectId="Employee">
  ///             &lt;bindings>
  ///               &lt;add name="Age" ignore="true"/>
  ///             &lt;/bindings>
  ///           &lt;/add>
  ///         &lt;/mappings>
  ///       &lt;/add>
  ///       &lt;add name="GetAddressById" 
  ///            queryBuilder="Generic" 
  ///            sql="select id, street, number, zip from address where id= :Id">
  ///         &lt;mappings>
  ///           &lt;add name="Mapping1" objectId="Address"/>
  ///         &lt;/mappings>
  ///       &lt;/add>
  ///     &lt;/queries>
  ///     &lt;objects>
  ///       &lt;assemblies>
  ///         &lt;add name="MyAssembly" value="ELE.EnterpriseLibrary.Test"/>
  ///       &lt;/assemblies>
  ///       &lt;types>
  ///         &lt;add name="Employee" type="ELE.EnterpriseLibrary.Test.Employee" assembly="MyAssembly"/>
  ///         &lt;add name="Address" type="ELE.EnterpriseLibrary.Test.Address" assembly="MyAssembly"/>
  ///         &lt;add name="Alias" type="ELE.EnterpriseLibrary.Test.Alias" assembly="MyAssembly"/>
  ///         &lt;add name="Equipment" type="ELE.EnterpriseLibrary.Test.Equipment" assembly="MyAssembly"/>
  ///       &lt;/types>
  ///     &lt;/objects>
  ///     &lt;mappings>
  ///       &lt;add name="Mapping1" queryBuilder="Generic">
  ///         &lt;objects>
  ///           &lt;add name="Employee" primaryTable="employee">
  ///             &lt;tables>
  ///               &lt;add name="employee">
  ///                 &lt;bindings>
  ///                   &lt;add name="Id" property="Id" sqlType="INT" inName="@Id" outName="id" column="id" primaryKey="true"/>
  ///                   &lt;add name="Name" property="Name" sqlType="VARCHAR" inName="@Name" outName="name" column="name" />
  ///                   &lt;add name="Address" property="Address" refType="Address" outName="addressId" inName="@AddressId" column="addressId" />
  ///                   &lt;add name="Aliases" property="Aliases" refType="Alias" collection="true" jointBinding="EmployeeId"/>
  ///                   &lt;add name="Equipment" property="Equipment" refType="Equipment" collection="true" inName="@EmployeeId" jointColumn="employeeId"/>
  ///                 &lt;/bindings>
  ///               &lt;/add>
  ///               &lt;add name="employee_extra" jointColumn="employeeId">
  ///                 &lt;bindings>
  ///                   &lt;add name="Age" property="Age" sqlType="INT" inName="@Age" outName="age" column="age"/>
  ///                   &lt;add name="BirthDate" property="BirthDate" sqlType="DATETIME" inName="@BirthDate" outName="birthDate" column="birthDate" nullableValue="datetime.minvalue"/>
  ///                 &lt;/bindings>
  ///               &lt;/add>
  ///             &lt;/tables>
  ///           &lt;/add>
  ///           &lt;add name="Address">
  ///             &lt;tables>
  ///               &lt;add name="address">
  ///                 &lt;bindings>
  ///                   &lt;add name="Id" property="Id" sqlType="INT" inName="@Id" outName="id" column="id" primaryKey="true"/>
  ///                   &lt;add name="StreetName" property="StreetName" sqlType="VARCHAR" inName="@StreetName" outName="street" column="street"/>
  ///                   &lt;add name="UnitNumber" property="UnitNumber" sqlType="VARCHAR" inName="@UnitNumber" outName="number" column="number"/>
  ///                   &lt;add name="ZipCode" property="ZipCode" sqlType="VARCHAR" inName="@ZipCode" outName="zip" column="zip"/>
  ///                 &lt;/bindings>                
  ///               &lt;/add>
  ///             &lt;/tables>
  ///           &lt;/add>
  ///           &lt;add name="Alias" primaryTable="aliases">
  ///             &lt;tables>
  ///               &lt;add name="aliases">
  ///                 &lt;bindings>
  ///                   &lt;add name="Id" property="Id" sqlType="INT" inName="@Id" column="id" primaryKey="true"/>
  ///                   &lt;add name="EmployeeId" property="EmployeeId" sqlType="INT" inName="@EmployeeId" column="parentId"/>
  ///                   &lt;add name="Value" property="Value" sqlType="VARCHAR" inName="@Value" column="value"/>
  ///                 &lt;/bindings>
  ///               &lt;/add>
  ///             &lt;/tables>
  ///           &lt;/add>
  ///           &lt;add name="Equipment">
  ///             &lt;tables>
  ///               &lt;add name="employee_equipment">
  ///                 &lt;bindings>
  ///                   &lt;add name="Id" property="Id" sqlType="INT" inName="@Id" column="id" primaryKey="true"/>
  ///                   &lt;add name="SerialNumber" property="SerialNumber" sqlType="VARCHAR" inName="@SerialNumber" column="serialNumber"/>
  ///                 &lt;/bindings>
  ///               &lt;/add>
  ///             &lt;/tables>
  ///           &lt;/add>
  ///         &lt;/objects>
  ///       &lt;/add>
  ///     &lt;/mappings>
  ///     &lt;queryBuilders>
  ///       &lt;add  name="Generic" type="ELE.EnterpriseLibrary.Data.GenericSqlQueryBuilder, ELE.EnterpriseLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"  default="true"/>
  ///     &lt;/queryBuilders>
  ///   &lt;/objectSqlMapping>
  /// &lt;/configuration>
  /// </code>
  /// </summary>
  public class ObjectMappingSettings : SerializableConfigurationSection
  {
    private const string queriesProperty = "queries";
    private const string objectsProperty = "objects";
    private const string mappingsProperty = "mappings";
    private const string queryBuildersProperty = "queryBuilders";
    private const string defaultQueryProperty = "defaultQuery";
    private const string defaultMappingProperty = "defaultMapping";
    private const string storedProceduresProperty = "storedProcedures";
    /// <summary>
    /// The name of the data configuration section.
    /// </summary>
    public const string SectionName = "objectSqlMapping";
    /// <summary>
    /// Default constructor used by the factory
    /// </summary>
    public ObjectMappingSettings()
      : base()
    {
    }
    /// <summary>
    /// Gets the object to sql mapping settings section from the configuration source
    /// </summary>
    /// <param name="configurationSource"></param>
    /// <returns></returns>
    public static ObjectMappingSettings GetObjectMappingSettings(IConfigurationSource configurationSource)
    {
      return (ObjectMappingSettings)configurationSource.GetSection(SectionName);
    }

    /// <summary>
    /// Gets the collection of <see cref="SqlQueryData"/> configuration elements that define 
    /// the available <see cref="ObjectSqlQuery"/>s.
    /// </summary>
    [ConfigurationProperty(queriesProperty)]
    public NamedElementCollection<SqlQueryData> Queries
    {
      get
      {
        return (NamedElementCollection<SqlQueryData>)base[queriesProperty];
      }
    }
    /// <summary>
    /// Gets the <see cref="ObjectQueryData"/> configuration element that defines 
    /// the available object types.
    /// </summary>
    [ConfigurationProperty(objectsProperty)]
    public ObjectQueryData Objects
    {
      get
      {
        return (ObjectQueryData)base[objectsProperty];
      }
      set
      {
        base[objectsProperty] = value;
      }
    }

    /// <summary>
    /// Gets the collection of <see cref="MappingQueryData"/> configuration elements that define 
    /// the available <see cref="ObjectSqlMapping"/>s.
    /// </summary>
    [ConfigurationProperty(mappingsProperty)]
    public NamedElementCollection<MappingQueryData> Mappings
    {
      get
      {
        return (NamedElementCollection<MappingQueryData>)base[mappingsProperty];
      }
    }

    /// <summary>
    /// Gets the collection of <see cref="QueryBuilderData"/> configuration elements that define 
    /// the available query builders.
    /// </summary>
    [ConfigurationProperty(queryBuildersProperty)]
    public NamedElementCollection<QueryBuilderData> QueryBuilders
    {
      get
      {
        return (NamedElementCollection<QueryBuilderData>)base[queryBuildersProperty];
      }
    }
    /// <summary>
    /// Sets and gets the name of the default <see cref="SqlQueryData"/>.
    /// </summary>
    [ConfigurationProperty(defaultQueryProperty, IsRequired = true)]
    public string DefaultQuery
    {
      get { return (string)base[defaultQueryProperty]; }
      set { base[defaultQueryProperty] = value; }
    }

    /// <summary>
    /// Sets and gets the name of the default <see cref="MappingQueryData"/>.
    /// </summary>
    [ConfigurationProperty(defaultMappingProperty, IsRequired = true)]
    public string DefaultMapping
    {
      get { return (string)base[defaultMappingProperty]; }
      set { base[defaultMappingProperty] = value; }
    }

    /// <summary>
    /// Gets the collection of <see cref="StoredProcedureData"/> configuration elements that define 
    /// the available <see cref="ObjectStoredProcedure"/>s.
    /// </summary>
    [ConfigurationProperty(storedProceduresProperty)]
    public NamedElementCollection<StoredProcedureData> StoredProcedures
    {
      get
      {
        return (NamedElementCollection<StoredProcedureData>)base[storedProceduresProperty];
      }
    }
  }
}
